/**
 *  @file  vsPerformance.h version 1.0 2007-11-20 
 *  @brief Definition of class Performance.
 *  Copyright (c) 2007 by @author <abitfree@gmail.com>
 */

#ifndef __VS_PERFORMANCE_H__
#define __VS_PERFORMANCE_H__

#include "vsTypes.h"
#include "vsDefines.h"

namespace vs
{

/**
 * @brief A simple performance testing class.
 *
 * A high qualified performance testing class.
 */
class Performance
{
private:

	/// Constants for performance.
	enum 
	{ 
		MAX_PERFORMANCE_POINT = 1024,	///< The max number of performance collection points.
		MAX_NAME = 32,					///< The max number of bytes of each point's name.
		MAX_FILE_NAME = 256,			///< The max length of a file name.
	};

	/// Performance collection point.
	typedef struct _collection_point
	{
		char	name[MAX_NAME]; 			///< The name for this point.
		int		id;							///< The id for this point.
		char	file[MAX_FILE_NAME];		///< The file name of this point.
		int		line;						///< The file line of this point.
		VS_INT64	time_stamp;				///< The timestamp when running at this point.
	} CollectionPoint;

	/// Performance data.
	typedef struct _performance_data
	{
		CollectionPoint	points[MAX_PERFORMANCE_POINT];	///< The points.
		int 			point_count;					///< The collected point count.
	} PerformanceData;

public:

	/// The constructor.
	Performance();

	/// The destructor.
	~Performance();

	/// Clear the collection points.
	void Clear();

	/// Print the timestamp of each point.
	void Print();

	/// Add a collection point.
	void AddCollectionPoint(const char *name, long id, const char *file, long line);

private:
	// Performance points.
	PerformanceData performance_data_;
};

INLINE
Performance::Performance()
{
	Clear();
}

INLINE
Performance::~Performance()
{
	Clear();
}

INLINE
void Performance::Clear()
{
	memset(&performance_data_, 0, sizeof(performance_data_));
}

INLINE
void Performance::Print()
{
	printf("performance data is...\n");
	for (int i=0; i<performance_data_.point_count; ++i)
	{
#ifdef _WIN32
		LARGE_INTEGER liFreq;
		QueryPerformanceFrequency(&liFreq);
		long double dfFreq = liFreq.QuadPart;

		printf("[%s %d %s %d] %f\n", performance_data_.points[i].name,
			performance_data_.points[i].id, performance_data_.points[i].file,
			performance_data_.points[i].line, performance_data_.points[i].time_stamp / dfFreq);
#else
		printf("[%s %d %s %d] %ld\n", performance_data_.points[i].name,
			performance_data_.points[i].id, performance_data_.points[i].file,
			performance_data_.points[i].line, performance_data_.points[i].time_stamp);
#endif
	}
}

INLINE
void Performance::AddCollectionPoint(const char *name, long id, const char *file, long line)
{
	if (performance_data_.point_count >= MAX_PERFORMANCE_POINT)
	{
		printf("performance point is equal to the upper-bound %d now, can not set any more\n", MAX_PERFORMANCE_POINT);
		return;
	}

	if (name != 0)
	{
		strncpy(performance_data_.points[performance_data_.point_count].name, name, MAX_NAME);
	}

	performance_data_.points[performance_data_.point_count].id = id;

	if (file != 0)
	{
		strncpy(performance_data_.points[performance_data_.point_count].file, file, MAX_FILE_NAME);
	}

	performance_data_.points[performance_data_.point_count].line = line;

#ifdef _WIN32
	LARGE_INTEGER liTimeStamp;
	QueryPerformanceCounter(&liTimeStamp);
	performance_data_.points[performance_data_.point_count].time_stamp = liTimeStamp.QuadPart;
#else
	struct timeval tp;
	gettimeofday(&tp, 0);
	performance_data_.points[performance_data_.point_count].time_stamp = tp.tv_sec * 1000000 + tp.tv_usec;
#endif

	++performance_data_.point_count;
}

} // namespace VS

#endif	// __VS_PERFORMANCE_H__
